﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using UIElements.Service;
using System.Windows;
using System.Windows.Input;

namespace UIElements.ViewModel
{
    public class PatternInstanceViewModel : TreeViewItemViewModel
    {
        #region Constructors

        public PatternInstanceViewModel()
            : base()
        {
            // initialize commands
            this.generateCodeCmd = new GenerateCodeCommand(this);
        }

        public PatternInstanceViewModel(TreeViewItemViewModel parent)
            : base(parent)
        {
            // initialize commands
            this.generateCodeCmd = new GenerateCodeCommand(this);
        }

        #endregion

        #region Properties

        private int patternInstanceID;
        public int PatternInstanceID
        {
            get { return patternInstanceID; }
            set
            {
                patternInstanceID = value;
                OnPropertyChanged("PatternInstanceID");
            }
        }

        private string patternInstanceName;
        public string PatternInstanceName
        {
            get { return patternInstanceName; }
            set
            {
                patternInstanceName = value;
                OnPropertyChanged("PatternInstanceName");
                //dataAccess.UpdateInstanceComment(patternInstanceID, instanceComments);
            }
        }

        private string instanceComments;
        public string InstanceComments
        {
            get { return instanceComments; }
            set
            {
                instanceComments = value;
                OnPropertyChanged("InstanceComments");
            }
        }

        private ICommand generateCodeCmd;
        public ICommand GenerateCodeCmd
        {
            get { return generateCodeCmd; }
        }

        #endregion

        #region Public Methods

        public override bool SaveChanges()
        {
            // save changes to DB
            var successful = dataAccess.SavePatternInstance(patternInstanceID, name: patternInstanceName, comments: instanceComments);
            if (!successful)
            {
                return false;
            }

            // update names of physical files
            UpdatePhysicalFileNames();

            return true;
        }

        /// <summary>
        /// get the table of properties of this pattern model
        /// </summary>
        /// <returns></returns>
        public override DataTable GetProperties()
        {
            // create new data table
            DataTable dtProperties = new DataTable();

            // create property name column
            DataColumn colPropertyName = new DataColumn("Property", typeof(string));
            dtProperties.Columns.Add(colPropertyName);

            // create property value column
            DataColumn colPropertyValue = new DataColumn("Value", typeof(string));
            dtProperties.Columns.Add(colPropertyValue);

            // add name row
            DataRow rowTemplateName = dtProperties.NewRow();
            dtProperties.Rows.Add(rowTemplateName);
            rowTemplateName["Property"] = "Instance Name";
            rowTemplateName["Value"] = patternInstanceName;

            // add comments row
            DataRow rowTemplateComments = dtProperties.NewRow();
            dtProperties.Rows.Add(rowTemplateComments);
            rowTemplateComments["Property"] = "Comments";
            rowTemplateComments["Value"] = instanceComments;
            
            // return the data table of properties
            return dtProperties;
        }

        public void UpdateAccordingToTemplate()
        {
            // get parent template
            var patternTemplate = Parent as PatternTemplateViewModel;

            // copy the template file
            var templateTemplateFilePath = IOService.GetPatternTemplateFilePath(patternTemplate.PatternTemplateName, PatternFileType.Template);
            var instanceTemplateFilePath = IOService.GetPatternInstanceFilePath(patternTemplate.PatternTemplateName, patternInstanceName, PatternFileType.Template);
            IOService.CopyFile(templateTemplateFilePath, instanceTemplateFilePath);

            // copy the x-frame file
            var templateXFrameFilePath = IOService.GetPatternTemplateFilePath(patternTemplate.PatternTemplateName, PatternFileType.XFrame);
            var instanceXFrameFilePath = IOService.GetPatternInstanceFilePath(patternTemplate.PatternTemplateName, patternInstanceName, PatternFileType.XFrame);
            IOService.CopyFile(templateXFrameFilePath, instanceXFrameFilePath);

            // make changes to the instance config file
            var templateConfigFilePath = IOService.GetPatternTemplateFilePath(patternTemplate.PatternTemplateName, PatternFileType.SPC);
            var htbTemplateVariables = IOService.LoadCodesAndVariablesFromConfig(templateConfigFilePath);
            var instanceConfigFilePath = IOService.GetPatternInstanceFilePath(patternTemplate.PatternTemplateName, patternInstanceName, PatternFileType.SPC);
            var htbInstanceVariables = IOService.LoadCodesAndVariablesFromConfig(instanceConfigFilePath);
            foreach (var key in htbTemplateVariables.Keys)
            {
                if (!htbInstanceVariables.ContainsKey(key))
                {
                    IOService.AddVariableToConfigFile(instanceConfigFilePath, key.ToString(), string.Empty);
                }
            }
            foreach (var key in htbInstanceVariables.Keys)
            {
                if (!htbTemplateVariables.ContainsKey(key))
                {
                    IOService.RemoveVariableFromConfigFile(instanceConfigFilePath, key.ToString());
                }
            }

            // generate and populate code
            GenerateAndPopulateCode();
        }

        #endregion

        #region Private Methods

        private void UpdatePhysicalFileNames()
        {
            // get the name of the pattern template
            var patternTemplateName = (Parent as PatternTemplateViewModel).PatternTemplateName;

            // get the old path to the instance directory
            var oldInstanceDirectory = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + PreviousName);

            // get the new path to the instance directory
            var newInstanceDirectory = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName);

            // update the name of the pattern instance directory
            IOService.RenameDirectory(oldInstanceDirectory, newInstanceDirectory);

            // update the name of the generated code file in the config file
            var instanceConfigFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.SPC);
            IOService.UpdateCodeFileNameInConfigFile(instanceConfigFile, patternInstanceName);

            // update the name of the generated code file if it exists
            var oldCodeFile = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName + @"\" + PreviousName + @".cs");
            var newCodeFile = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName + @"\" + patternInstanceName + @".cs");
            if (IOService.FileExists(oldCodeFile))
            {
                IOService.RenameFile(oldCodeFile, newCodeFile);
            }

            // update the name of the instance template file
            var oldInstanceTemplateFile = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName + @"\" + PreviousName + @".template");
            var newInstanceTemplateFile = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName + @"\" + patternInstanceName + @".template");
            if (IOService.FileExists(oldInstanceTemplateFile))
            {
                IOService.RenameFile(oldInstanceTemplateFile, newInstanceTemplateFile);
            }
        }

        public void GenerateAndPopulateCode()
        {
            // get path to the config file
            var patternTemplateName = (Parent as PatternTemplateViewModel).PatternTemplateName;
            var configFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.SPC);

            // get path to the code file
            var codeFilePath = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.Code);

            // delete the old code file if there is
            IOService.DeleteFile(codeFilePath);

            // generate code from the SPC file
            IOService.GenerateCodeFromTempate(configFile);

            // get the list of locations registered with this pattern
            var locationList = GetLocationList();

            // populate the generated code to corresponding registered locations
            IOService.PopulateCodeToLocations(codeFilePath, locationList);
        }

        private List<string> GetLocationList()
        {
            var locationList = new List<string>();

            // get the locations based on ID of the pattern instance
            var locations = dataAccess.GetAllPatternLocations(patternInstanceID);

            foreach (var location in locations)
            {
                locationList.Add(location.Path);
            }

            return locationList;
        }

        #endregion

        #region Commands

        #region Generate Code Command

        private void GenerateCode()
        {
            // get path to the SPC file
            var spcFilePath = IOService.GetPatternInstanceFilePath((Parent as PatternTemplateViewModel).PatternTemplateName,
                                                                    patternInstanceName, PatternFileType.SPC);

            // generate code from the SPC file
            IOService.GenerateCodeFromTempate(spcFilePath);

            // notify successful code generation
            // MessageBox.Show("Code generated successfully!");

        }

        public class GenerateCodeCommand : ICommand
        {
            private PatternInstanceViewModel viewModel;

            public GenerateCodeCommand(PatternInstanceViewModel viewModel)
            {
                this.viewModel = viewModel;
                this.viewModel.PropertyChanged += (sender, e) =>
                {
                    if (this.CanExecuteChanged != null)
                    {
                        this.CanExecuteChanged(this, new EventArgs());
                    }
                };
            }

            public bool CanExecute(object parameter)
            {
                //return viewModel.PatternTemplates.Count != 0;
                return true;
            }

            public event EventHandler CanExecuteChanged;

            public void Execute(object parameter)
            {
                this.viewModel.GenerateCode();
            }
        }

        #endregion

        #endregion
    }
}
